#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "pileport.h"



// crée une pile de portée avec un premier niveau 0 vide 
// et retourne un pointeur
pileport* creerPilePortee()
{
	portee* p = creerPortee(0);
	pileport* pp = (pileport*)malloc(sizeof(pileport));
	pp->tete = p;
	pp->next = NULL;
	return pp;
}

// ajoute un niveau de portee vide à la pile de portee
pileport* addPortee(pileport* pp, int lvl)
{
    int level = lvl; //getMaxLevelPP(pp)+1;
	portee*p = creerPortee(level);
	pileport* aux = (pileport*)malloc(sizeof(pileport));
	aux->tete = p;
	aux->next = pp;
	return aux;
}

// retourne la portee la plus haute de la pile de portee
int getMaxLevelPP(pileport* pp)
{
	int res;
	pileport* it = pp;
	
	if (it == NULL)	
		res = -1;
	else
		res = pp->tete->level;
	return res;
}

//cree une portee avec un level, la liste d'entrees est vide
portee* creerPortee(int level)
{
	portee* p = (portee*)malloc(sizeof(portee));
	p->level = level;
	p->listEntries = NULL;
	return p;
}

// ajoute une entree à la pile de portee
// si le niveau existe ajoute
// si n'existe pas, verifie que le niveau n-1 existe et le crée 
pileport* addEntryToPP(pileport*pp, entree* e, int level)
{
    if (level != -1)
    {
        // tester si le niveau recherché est correct
        int maxPP = getMaxLevelPP(pp);
       /* if (level > maxPP+1)
        {
            printf("erreur de niveau dans la pile de portee.\nTentative d'ajout d'un niveau %i alors que le niveau actuel est %i\n", level, maxPP);
            return NULL;
        }*/

        // créer un nouveau niveau si nécessaire
        if (level > maxPP)
            pp = addPortee(pp,level);

        // se placer sur le bon niveau
        pileport* itPP = pp;
        while(itPP->tete->level > level)
            itPP = itPP->next;

        // ajouter en tête
        entreePP* listeEntreesPP = itPP->tete->listEntries;
        entreePP* aux = createEntryPP(e);
        aux->next = listeEntreesPP;
        itPP->tete->listEntries = aux;

    }
    /*else
    {
        printf("ajout d'une entrée avec niveau -1 (constante)\n");
        printf("cette entrée n'est pas ajoutée dans la pile de portée\n");
    }*/

    return pp;
}

entreePP* createEntryPP(entree* e)
{
	entreePP* res = (entreePP*)malloc(sizeof(entreePP));
	res->e = e;
	res->next = NULL;
	return res;
}


// supprime un niveau de la pile de portee
// ainsi que la liste des entrées
pileport* popPortee(pileport* pp)
{
    if(pp !=NULL)
    {
        pileport* aux = pp->next;
        pp->tete = supprimerPortee(pp->tete);
        free(pp);
        pp = NULL;
        return aux;
    }
    /*else
    {
        fprintf(stderr,"attention appel de popLevel, pile déjà NULL\n");
        return NULL;
    }*/
}



portee* supprimerPortee(portee* p)
{
	p->listEntries = supprimerListEntries(p->listEntries);
	free(p);
	p = NULL;
	return p;
}

// supprime la liste d'entrées
// et depile la definition la + haute de chaque entrée concernée
entreePP* supprimerListEntries(entreePP* list)
{
	entreePP* aux ;
	entree* dest;
	
	// si une seule entrée
	if(list->next == NULL)
	{
		aux = list;
		dest = aux->e;
		dest->definitioncourante = popPileDef(dest->definitioncourante);
		aux = NULL;		
	}
	
	else
	{
		while(list->next != NULL)
		{			
			aux = list;
			list = list->next;
			dest = aux->e;
			dest->definitioncourante = popPileDef(dest->definitioncourante);
			free(aux);
			aux = NULL;
		}
		aux=list;
		dest = aux->e;
		dest->definitioncourante = popPileDef(dest->definitioncourante);		
		aux = NULL;	
	}
		
	free(list);
	list=NULL;
	return list;	
}




/*
pileport* supprimerPilePortee(pileport* pp)
{
	while(pp->next)
		pp = popPortee(pp);
	pp->tete = supprimerPortee(pp->tete);
	free(pp);
	pp = NULL;
	return pp;
}*/
